/*
 * @Author: 吴世扬 18368095041@163.com
 * @Date: 2025-02-19 09:06:40
 * @LastEditors: 吴世扬 18368095041@163.com
 * @LastEditTime: 2025-02-25 17:29:44
 * @FilePath: /vue3-admin-server/src/services/menu.service.ts
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { MenuEntity } from 'src/entities/menu.entity';
import { MenuListDTO, MenuDTO } from 'src/common/dto';
import { arrayToTreeByField } from 'src/common/utils';

@Injectable()
export class MenuService {
    constructor(
        @InjectRepository(MenuEntity)
        private readonly menuRepository: Repository<MenuEntity>
    ) {}

    async readList(
        menuListDTO: MenuListDTO
    ): Promise<VO.PageDataVO<VO.MenuVO>> {
        const { current, size, sortList, ...rest } = menuListDTO;

        // 构建查询
        const queryBuilder = this.menuRepository
            .createQueryBuilder('menu')
            .where(rest);

        // 应用排序
        if (sortList && sortList.length > 0) {
            sortList.forEach((sort) => {
                queryBuilder.addOrderBy(
                    `menu.${sort.column}`,
                    sort.order.toUpperCase() as 'ASC' | 'DESC'
                );
            });
        }

        // 获取总数
        const total = await queryBuilder.getCount();

        // 获取分页数据
        const menuList = await queryBuilder
            .skip((current - 1) * size)
            .take(size)
            .getMany();

        return {
            current: menuListDTO.current,
            size: menuListDTO.size,
            total,
            records: menuList
        };
    }

    async readAll(): Promise<VO.MenuVO[]> {
        const queryBuilder = this.menuRepository.createQueryBuilder('menu');
        return queryBuilder.getMany();
    }

    async readTree(): Promise<VO.MenuTreeVO[]> {
        const menuList = await this.readAll();

        return arrayToTreeByField(
            menuList,
            'id',
            'parentId',
            (a, b) => b.sortWeight - a.sortWeight
        );
    }

    async readDetail(id: number): Promise<VO.MenuVO | null> {
        const queryBuilder = this.menuRepository
            .createQueryBuilder('menu')
            .where({
                id
            });
        const data = await queryBuilder.getOne();
        return data;
    }

    async save(menuDTO: MenuDTO): Promise<number | Error> {
        let result: number | Error;
        try {
            const queryBuilder = this.menuRepository.createQueryBuilder('menu');
            if (menuDTO.id) {
                const { id, ...rest } = menuDTO;
                await queryBuilder
                    .update(MenuEntity)
                    .set(rest)
                    .where('id = :id', { id })
                    .execute();
                result = id;
            } else {
                const { identifiers } = await queryBuilder
                    .insert()
                    .into(MenuEntity)
                    .values(menuDTO)
                    .execute();
                result = identifiers[0].id as number;
            }
            return Promise.resolve(result);
        } catch (e) {
            result = e as Error;
            return Promise.reject(result);
        }
    }

    async delete(id: number): Promise<true | Error> {
        try {
            const queryBuilder = this.menuRepository.createQueryBuilder('menu');
            await queryBuilder
                .delete()
                .from(MenuEntity)
                .where('id = :id', { id })
                .execute();
            return Promise.resolve(true);
        } catch (e) {
            return Promise.reject(e as Error);
        }
    }
}
